package com.yc.sole.erp.repository;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.sole.common.domain.StateCountResp;
import com.yc.sole.erp.dto.ProduceDto;
import com.yc.sole.erp.entity.Produce;
import com.yc.sole.erp.enums.ProduceState;
import com.yc.sole.erp.exception.ErpResultEnum;
import com.yc.sole.erp.mapper.ProduceMapper;
import com.yc.sole.erp.request.ProduceQueryReq;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.mybatis.page.Paging;
import com.yc.sole.framework.mybatis.util.PageUtil;
import com.yc.sole.framework.result.BaseResultEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 服务接口实现
 *
 * @author yizuomin
 * @date 2024-01-13
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class ProduceRepository extends ServiceImpl<ProduceMapper, Produce> {

    /**
     * 新增
     *
     * @param produceDto
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveProduce(ProduceDto produceDto) {
        Produce produce = new Produce();
        BeanUtil.copyProperties(produceDto, produce);
        this.save(produce);
    }

    /**
     * 通过Id修改
     *
     * @param produceDto
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateProduceById(ProduceDto produceDto) {
        Produce entity = new Produce();
        BeanUtil.copyProperties(produceDto, entity);
        this.updateById(entity);
    }

    /**
     * 修改生产状态
     *
     * @param id
     * @param produceState
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateProduceState(Long id, ProduceState produceState) {
        LambdaUpdateWrapper<Produce> wrapper = Wrappers.<Produce>lambdaUpdate()
                .eq(Produce::getId, id)
                .set(Produce::getProduceState, produceState);
        boolean update = this.update(wrapper);
        if (!update) {
            throw new BaseException(BaseResultEnum.FAIL);
        }
    }

    /**
     * 通过id删除
     *
     * @param id
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteProduce(Long id) {
        this.removeById(id);
    }

    /**
     * 通过id删除
     *
     * @param ids
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteProduceByIds(Collection<Long> ids) {
        this.removeBatchByIds(ids);
    }

    /**
     * 根据id获取
     *
     * @param ids
     * @return RestResult
     */
    public List<ProduceDto> selectProduceByIds(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return BeanUtil.copyToList(this.listByIds(ids), ProduceDto.class);
    }

    /**
     * 根据订单id获取
     *
     * @param orderId
     * @return RestResult
     */
    public ProduceDto selectByOrderId(Long orderId) {
        LambdaQueryWrapper<Produce> wrapper = Wrappers.<Produce>lambdaQuery().eq(Produce::getOrderId, orderId);
        return BeanUtil.copyProperties(this.getOne(wrapper), ProduceDto.class);
    }

    /**
     * 根据id获取
     *
     * @param id
     * @return RestResult
     */
    public ProduceDto selectProduceById(Long id) {
        return BeanUtil.copyProperties(this.getById(id), ProduceDto.class);
    }

    /**
     * 分页查询
     *
     * @param page
     * @return RestResult
     */
    public Paging<ProduceDto> selectProducePage(Paging page, ProduceQueryReq queryReq) {
        LambdaQueryWrapper<Produce> wrapper = this.getWrapper(queryReq);
        return PageUtil.pageCopy(this.page(PageUtil.toMybatisPage(page), wrapper), ProduceDto.class);
    }

    /**
     * 分页查询可以产量登记的生产中信息
     *
     * @param page
     * @return RestResult
     */
    public Paging<ProduceDto> selectProduceRegistrationPage(Paging page, ProduceQueryReq queryReq) {
        LambdaQueryWrapper<Produce> wrapper = this.getWrapper(queryReq);
        wrapper.gt(Produce::getRemainingQuantity, 0)
                .eq(Produce::getProduceState, ProduceState.IN_PRODUCTION);
        return PageUtil.pageCopy(this.page(PageUtil.toMybatisPage(page), wrapper), ProduceDto.class);
    }

    /**
     * 分页查询可以产量登记的生产中信息
     *
     * @param queryReq
     * @return RestResult
     */
    public List<ProduceDto> selectProduceRegistrationList(ProduceQueryReq queryReq) {
        LambdaQueryWrapper<Produce> wrapper = this.getWrapper(queryReq);
        wrapper.gt(Produce::getRemainingQuantity, 0)
                .eq(Produce::getProduceState, ProduceState.IN_PRODUCTION);
        return BeanUtil.copyToList(this.list(wrapper), ProduceDto.class);
    }

    private LambdaQueryWrapper<Produce> getWrapper(ProduceQueryReq queryReq) {
        LambdaQueryWrapper<Produce> wrapper = Wrappers.<Produce>lambdaQuery()
                .like(CharSequenceUtil.isNotBlank(queryReq.getProduceNo()), Produce::getProduceNo, queryReq.getProduceNo())
                .like(CharSequenceUtil.isNotBlank(queryReq.getOrderNo()), Produce::getOrderNo, queryReq.getOrderNo())
                .eq(CharSequenceUtil.isNotBlank(queryReq.getProduceDate()), Produce::getProduceDate, queryReq.getProduceDate())
                .eq(Objects.nonNull(queryReq.getProductId()), Produce::getProductId, queryReq.getProductId())
                .eq(Objects.nonNull(queryReq.getCustomerId()), Produce::getCustomerId, queryReq.getCustomerId())
                .eq(Objects.nonNull(queryReq.getPriority()), Produce::getPriority, queryReq.getPriority())
                .eq(Objects.nonNull(queryReq.getProduceState()), Produce::getProduceState, queryReq.getProduceState())
                .eq(Objects.nonNull(queryReq.getSourceType()), Produce::getSourceType, queryReq.getSourceType())
                .and(CharSequenceUtil.isNotBlank(queryReq.getKeyword()),
                        w -> w.like(Produce::getProductName, queryReq.getKeyword())
                                .or().like(Produce::getCustomerName, queryReq.getKeyword())
                                .or().like(Produce::getProduceNo, queryReq.getKeyword())
                                .or().like(Produce::getOrderNo, queryReq.getKeyword())
                                .or().like(Produce::getProduceDate, queryReq.getKeyword()))
                .orderByAsc(Objects.nonNull(queryReq.getSortType()) && queryReq.getSortType() == 0, Produce::getRemainingQuantity)
                .orderByDesc(Objects.nonNull(queryReq.getSortType()) && queryReq.getSortType() == 1, Produce::getRemainingQuantity)
                .orderByDesc(Produce::getCustomerId)
                .orderByAsc(Produce::getProduceState)
                .orderByDesc(Produce::getPriority, Produce::getCustomerId, Produce::getId);
        if (CollUtil.isNotEmpty(queryReq.getProduceDateRange())
                && CharSequenceUtil.isNotBlank(queryReq.getProduceDateRange().get(0))
                && CharSequenceUtil.isNotBlank(queryReq.getProduceDateRange().get(1))) {
            wrapper.between(Produce::getProduceDate, queryReq.getProduceDateRange().get(0), queryReq.getProduceDateRange().get(1));
        }
        return wrapper;
    }

    /**
     * 查询生产状态的数量
     *
     * @return
     */
    public List<StateCountResp> selectProduceStateCount(ProduceQueryReq queryReq) {
        return this.baseMapper.selectProduceStateCount(queryReq);
    }

    /**
     * 变更生产余数
     *
     * @param id
     * @param updateQuantity 变动数量 正数为加 负数为减
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateRemainingQuantity(Long id, Integer updateQuantity) {
        if (updateQuantity == null || updateQuantity == 0) {
            return;
        }
        // 查询
        ProduceDto produceDto = this.selectProduceById(id);
        if (Objects.isNull(produceDto)) {
            throw new BaseException(ErpResultEnum.PRODUCE_NOT_FOUND);
        }
        // 新的剩余数量
        int newRemainingQuantity = produceDto.getRemainingQuantity() + updateQuantity;
        // 余数不足
        if (newRemainingQuantity < 0) {
            throw new BaseException(ErpResultEnum.PRODUCE_REMAIN_QUANTITY_NOT_ENOUGH, produceDto.getRemainingQuantity());
        }
        LambdaUpdateWrapper<Produce> wrapper = Wrappers.<Produce>lambdaUpdate()
                .eq(Produce::getId, id)
                .eq(Produce::getRemainingQuantity, produceDto.getRemainingQuantity())
                .set(Produce::getRemainingQuantity, newRemainingQuantity)
                .set(newRemainingQuantity == 0, Produce::getProduceState, ProduceState.FINISHED)
                .set(newRemainingQuantity == 0, Produce::getProduceEndDate, DateUtil.today())
                .set(newRemainingQuantity > 0, Produce::getProduceState, ProduceState.IN_PRODUCTION)
                .set(newRemainingQuantity > 0, Produce::getProduceEndDate, null);
        boolean update = this.update(wrapper);
        if (!update) {
            throw new BaseException(BaseResultEnum.FAIL);
        }

    }

    /**
     * 根据排产编号查询
     *
     * @param produceNo
     * @return
     */
    public List<ProduceDto> selectByProduceNoLike(String produceNo) {
        LambdaQueryWrapper<Produce> wrapper = Wrappers.<Produce>lambdaQuery()
                .like(CharSequenceUtil.isNotBlank(produceNo), Produce::getProduceNo, produceNo);
        Page<Produce> page = new Page<>(1, 10);
        return BeanUtil.copyToList(this.page(page, wrapper).getRecords(), ProduceDto.class);
    }

    /**
     * 根据排产编号查询
     *
     * @param produceNos
     * @return
     */
    public List<ProduceDto> selectByProduceNos(Collection<String> produceNos) {
        LambdaQueryWrapper<Produce> wrapper = Wrappers.<Produce>lambdaQuery()
                .in(Produce::getProduceNo, produceNos);
        return BeanUtil.copyToList(this.list(wrapper), ProduceDto.class);
    }
}
